package com.hitqz.robot.util;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hitqz.robot.camera.communication.NetworkServiceThreadPool;
import com.hitqz.robot.camera.communication.TcpServer;
import com.hitqz.robot.netty.decoder.HitChipDecoder;
import com.hitqz.robot.netty.encoder.HitChipEncoder;
import com.hitqz.robot.netty.handler.HitChipMessageHandler;
import com.hitqz.robot.netty.handler.IpBlacklistHandler;
import com.hitqz.robot.netty.message.ChipMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * chip-处理
 * @author xupkun
 * @date 2024/11/3
 */
@Slf4j
public class ChipToolKit {

    protected static volatile Map<String, ChannelHandlerContext> currentTable  = Maps.newHashMap();
    private static final ChannelGroup GlobalGroup=new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    public static List<String> GlobalId = Lists.newArrayList();


    public static final Set<String> blacklist = Collections.synchronizedSet(new HashSet<>());

    public static TcpServer server;
    private final static int defaultPort = 8081;

    public static final ConcurrentHashMap<String, CompletableFuture<Boolean>> requestMap = new ConcurrentHashMap<>();


    public static boolean init(Integer port){
        int bindPort = port == null?  defaultPort : port;
        if (server == null){
            server = new TcpServer("hitChip", bindPort, new ChannelInitializer<Channel>() {
                @Override
                protected void initChannel(Channel channel) throws Exception {
                    channel.pipeline().addLast("ipHandler",new IpBlacklistHandler(blacklist));
                    channel.pipeline().addLast("frameDecoder", new LengthFieldBasedFrameDecoder(1024, 2, 1, 1, 0));
                    channel.pipeline().addLast("decoder", new HitChipDecoder());
                    channel.pipeline().addLast("encoder", new HitChipEncoder());
                    channel.pipeline().addLast("handler", new HitChipMessageHandler());
                }
            });
            NetworkServiceThreadPool.creatNetworkServerOrClient(()->{
                try {
                    log.info("hit-chip 绑定端口:" + port);
                    server.bind();
                } catch (InterruptedException e) {
                    log.error("[track] server bind error", e);
                }
            });
        }
        return true;
    }


    public static String bytesToHexString(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) { // 将字节转为无符号的十六进制字符串
            String hex = String.format("%02X", bytes[i] & 0xFF);
            hexString.append(hex);
            if (i < bytes.length - 1) {
                hexString.append(" ");
            }
        }
        return hexString.toString();
    }


    public static void addChannel(String ip, ChannelHandlerContext ctx) {
        if(findByChannelId(ctx.channel().id()) == null) {
            GlobalGroup.add(ctx.channel());
            currentTable.put(ip , ctx);
            log.info("add channel  ---- {}", ip);
            GlobalId.add(ip);
        } else {
            log.info("channel already exists:{}, {}", ip);
        }
    }


    public static Channel findByChannelId(ChannelId channelId) {
        return GlobalGroup.find(channelId);
    }

    /**
     *
     * @param id
     * @return
     */
    public static ChannelHandlerContext findByIpAddress(String id) {
        return currentTable.get(id);
    }

    public static void removeChannel(String id, ChannelHandlerContext ctx) {
        Channel  channel = findByChannelId(ctx.channel().id());
        if (channel != null) {
            GlobalGroup.remove(channel);
            currentTable.remove(id);
        }
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (Exception e) {

        }
    }

    public static void setJackDistance(String ip, int jackDistance) {
        ChannelHandlerContext ctx = findByIpAddress(ip);
        ByteBuf buffer = ctx.alloc().buffer(6);
        try {
            buffer.writeByte(0x1F);
            buffer.writeByte(0x01);
            buffer.writeByte(0x09);//推杆
            buffer.writeByte(0x01);//设置距离命令
            buffer.writeIntLE(jackDistance);
            // 获取 ByteBuf 中的数据到字节数组中
            byte[] bytes = new byte[buffer.readableBytes()];
            buffer.getBytes(0, bytes);
            ChipMessage chipMessage = new ChipMessage(bytes);
            ctx.writeAndFlush(chipMessage);
        } finally {
            // 确保 ByteBuf 在使用完后释放，防止内存泄漏
            buffer.release();
        }
    }





    public static void sendData(String ip, byte[] data) {
        ChipMessage chipMessage = new ChipMessage();
        chipMessage.setData(data);
        ChannelHandlerContext channel = findByIpAddress(ip);
        if (channel != null) {
            channel.writeAndFlush(chipMessage);
        }

    }


    public static void release(ChipMessage trackMessage,boolean hasSubCmd,boolean result){
        byte[] data = trackMessage.getData();
        String hexKey;
        if (hasSubCmd){
            //有子命令的
            hexKey = String.format("%02X%02X", data[0], data[1]);
        }else {
            //没有子命令的
            hexKey = String.format("%02X", data[0]);
        }
        CompletableFuture<Boolean> future = requestMap.remove(hexKey);
        if (future != null) {
            future.complete(result);
            log.debug("[track]cmd:{},release",trackMessage.getCmdHexStr());
        }
    }



}
